package com.rookie.data.generate.component;

import com.rookie.data.generate.DataGenerateApplication;
import com.rookie.data.generate.constant.annotation.*;
import com.rookie.data.generate.model.project.FieldProperties;
import com.rookie.data.generate.util.GenerateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * 组件扫描注册器
 *
 * @author rookie
 */
public class GenerateScanRegister implements ImportBeanDefinitionRegistrar {

    private static final Map<String, Map<String, FieldProperties>> FIELD_PROPERTIES = new HashMap<>();

    /**
     * 容器：值来源于其他表的字段
     */
    public static final Map<String, Map<String, String>> DEPENDENT_COLUMN = new HashMap<>();

    /**
     * 关联表生成的配置
     */
    public static final Map<String, String[]> MEANTIME_TABLE = new HashMap<>();

    private static AnnotationAttributes historyAttributes = null;

    public static final GenerateScanRegister REGISTER = new GenerateScanRegister();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        refreshFieldProperties(importingClassMetadata, registry);
    }

    public void refreshFieldProperties(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        scanAnnotationGenerate();
        Set<BeanDefinition> beanDefinitions = scanTableBeanDefinition(importingClassMetadata, registry);
        analyseTableFieldProperties(beanDefinitions);
    }

    private void scanAnnotationGenerate() {
        ClassPathScanningCandidateComponentProvider classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false);
        classPathScanningCandidateComponentProvider.addIncludeFilter(new ComponentFilter());
        Set<BeanDefinition> candidateComponents = classPathScanningCandidateComponentProvider.findCandidateComponents(DataGenerateApplication.class.getPackage().getName());
        candidateComponents.forEach(p -> {
            if (StringUtils.isNotBlank(p.getBeanClassName())) {
                Class<?> aClass = ClassUtils.resolveClassName(p.getBeanClassName(), null);
                boolean assignableFrom = AbstractAnnotationGenerate.class.isAssignableFrom(aClass);
                if (assignableFrom) {
                    try {
                        AbstractAnnotationGenerate abstractAnnotationGenerate = (AbstractAnnotationGenerate) aClass.newInstance();
                        BeanContainer.generateAnnotation.put(abstractAnnotationGenerate.getAnnotationClass(), abstractAnnotationGenerate);
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    private Set<BeanDefinition> scanTableBeanDefinition(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false);
//        添加自定义筛选器，筛选 @GenerateTable 实体类
        classPathScanningCandidateComponentProvider.addIncludeFilter(new GenerateTableFilter());
        String[] scanArray = new String[0];
        AnnotationAttributes generateScanAttrs = null;
        //        获取配置的扫描路径
        if (importingClassMetadata == null){
            if (historyAttributes == null){
                throw new RuntimeException("importingClassMetadata 与 historyAttributes 为空，操作失败");
            }
            generateScanAttrs = historyAttributes;
        }else{
            generateScanAttrs = AnnotationAttributes
                    .fromMap(importingClassMetadata.getAnnotationAttributes(GenerateScan.class.getName()));
            historyAttributes = generateScanAttrs;
        }


        if (generateScanAttrs != null) {
            scanArray = generateScanAttrs.getStringArray("value");
        }
        Set<BeanDefinition> tableArray = new HashSet<>();
        if (scanArray.length > 0) {
            for (String s : scanArray) {
                tableArray.addAll(classPathScanningCandidateComponentProvider.findCandidateComponents(s));
            }
        }
        return tableArray;
    }

    private void analyseTableFieldProperties(Set<BeanDefinition> tableArray) {
        for (BeanDefinition beanDefinition : tableArray) {
            if (StringUtils.isBlank(beanDefinition.getBeanClassName())) {
                continue;
            }
            Class<?> aClass = ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), null);
            GenerateTable generateTableAnnotation = aClass.getAnnotation(GenerateTable.class);
            if (generateTableAnnotation == null) {
                continue;
            }
            Field[] declaredFields = aClass.getDeclaredFields();
            Map<String, FieldProperties> fieldPropertiesMap = new HashMap<>(20);
//            判断实体类字段是否需要转下划线
            boolean toLineStatus = generateTableAnnotation.fieldUnderLine();
            Map<String, String> columnTmp = new HashMap<>();
            for (Field declaredField : declaredFields) {
                FieldProperties fieldPropertiesTmp = matchFieldProperties(declaredField);
                String fieldName = null;
                if (toLineStatus) {
                    fieldName = GenerateUtils.humpToLine(declaredField.getName(), false);
                } else {
                    fieldName = declaredField.getName();
                }
//                    获取每个字段的创建条件 FieldProperties
                fieldPropertiesMap.put(fieldName, fieldPropertiesTmp);

                if (StringUtils.isNotBlank(fieldPropertiesTmp.getExtractVale())) {
                    columnTmp.put(fieldName, fieldPropertiesTmp.getExtractVale());
                }
            }
            String tableName = null;
//            是否存在表别名
            if (StringUtils.isNotBlank(generateTableAnnotation.table())) {
                tableName = generateTableAnnotation.table();
            } else {
//                表名是否需要转下划线
                if (generateTableAnnotation.tableUnderLine()) {
                    tableName = GenerateUtils.humpToLine(aClass.getSimpleName(), true);
                } else {
                    tableName = aClass.getSimpleName();
                }
            }

            FIELD_PROPERTIES.put(tableName, fieldPropertiesMap);

            DEPENDENT_COLUMN.put(tableName,columnTmp);
            MEANTIME_TABLE.put(tableName,generateTableAnnotation.meantimeTable());
        }
    }

    public static FieldProperties getTableFieldProperties(String tableName, String columnName) {
        Map<String, FieldProperties> fieldPropertiesMap = FIELD_PROPERTIES.get(tableName);
        if (fieldPropertiesMap == null) {
            return null;
        }
        return fieldPropertiesMap.get(columnName);
    }

    public static Map<String, Map<String, FieldProperties>> getAllConfig() {
        return FIELD_PROPERTIES;
    }

    private FieldProperties matchFieldProperties(Field declaredField) {
        FieldProperties fieldProperties = new FieldProperties();
        Range sizeAnnotation = declaredField.getAnnotation(Range.class);
        if (sizeAnnotation != null) {
            fieldProperties.setMaxValue(sizeAnnotation.max());
            fieldProperties.setMinValue(sizeAnnotation.min());
            fieldProperties.setPointLength(sizeAnnotation.point());
        }

        StringTemplate stringTemplate = declaredField.getAnnotation(StringTemplate.class);
        if (stringTemplate != null) {
            fieldProperties.setStringTemplate(stringTemplate);
        }

        TimeRange timeRange = declaredField.getAnnotation(TimeRange.class);

        if (timeRange != null) {
            fieldProperties.setTimeRange(timeRange);
        }

        ConstCollection constCollection = declaredField.getAnnotation(ConstCollection.class);

        if (constCollection != null) {
            fieldProperties.setConstCollection(constCollection);
        }

        NullType nullType = declaredField.getAnnotation(NullType.class);

        if (nullType != null) {
            fieldProperties.setNullStatus(true);
        }

        Extract extract = declaredField.getAnnotation(Extract.class);

        if (extract != null) {
            fieldProperties.setExtractVale(extract.value());
        }

        fieldProperties.setAnnotations(new ArrayList<>());

        BeanContainer.generateAnnotation.forEach((v1, v2) -> {
            Annotation annotation = declaredField.getAnnotation(v1);
            if (annotation != null) {
                fieldProperties.getAnnotations().add(annotation);
            }
        });

        return fieldProperties;
    }

    static class GenerateTableFilter implements TypeFilter {

        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            return metadataReader.getAnnotationMetadata().isAnnotated(GenerateTable.class.getName());
        }
    }

    static class ComponentFilter implements TypeFilter {

        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            return metadataReader.getAnnotationMetadata().isAnnotated(Component.class.getName());
        }
    }
}
